
package slerp;

import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;


public class Main {
    //Variable declaration
    private static GameMap map = new GameMap();
    private static GameMap mapread = null;
    private static ArrayList<Drawable> render = new ArrayList<Drawable>(); //simpy contains the drawables to render each frame
    public static int x_max, y_max;
    HerpEngineTime timer;
    LinkedList<Block> blocks;
    Player player;
    //End of variable declaration
    public static void main(String[] args)  {
        
        map.addMember(0, new Empty());
        map.addMember(0, new Empty());
        map.addMember(0, new Block());
        
        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("level.iomap"));
            out.writeObject(map);
            out.close();
        } catch(IOException e) {
            System.out.println("herp");
        }
            
        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("level.iomap"));
            try {
                mapread = (GameMap) in.readObject();
            } catch (ClassNotFoundException ex) {
                System.out.println("Failed to identify class when trying to load");
            }
            in.close();
        } catch(IOException e) {
            System.out.println("File read error: " + e.getMessage());
        }
        
        mapread.debugPrintAllChunkMembers();
        
        try {
            Main m = new Main();
            m.mainLoop();
        } catch (InterruptedException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex.getStackTrace());
        } finally {
            destroy();
        }
        
        System.exit(0);
    
    }
    private void initDisplay(int width, int height) {
        try {
            Display.setDisplayMode(new DisplayMode(width, height));
            Display.create();
            Display.setVSyncEnabled(true);
            x_max = width;
            y_max = height;
        } catch(LWJGLException e) {
            System.exit(-1);
        }
    }
    
    private void initGL() {
        GL11.glEnable(GL11.GL_BLEND); // Enabled blending
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); // selects blending method
        GL11.glEnable(GL11.GL_ALPHA_TEST); // allows alpha channels or transperancy
        GL11.glAlphaFunc(GL11.GL_GREATER, 0.1f); // sets aplha function
    }
        
    private void logic() {
        long deltaTime = timer.getDeltaTime();
    }
    
    /**
     * Changes to a 2D optimized mode, and creates a glOrtho to give you a space to draw on
     * @param x Where the x in glOrtho is going to start. 
     * @param width Where the x in glOrtho is going to stop 
     * @param y Where the y in glOrtho is going to start.
     * @param height Where the y in glOrtho is going to stop.
     */
    private void set2DMode(float x, float width, float y, float height) {
        GL11.glDisable(GL11.GL_DEPTH_TEST);
    	GL11.glMatrixMode(GL11.GL_PROJECTION);                        // Select The Projection Matrix
        GL11.glPushMatrix();                                     // Store The Projection Matrix
        GL11.glLoadIdentity();                                   // Reset The Projection Matrix
        GL11.glOrtho(x, width, y, height, -1, 1);                 // Set Up An Ortho Screen 
        GL11.glTranslated(Display.getDisplayMode().getWidth() / 2, Display.getDisplayMode().getHeight() / 2, 0);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);                         // Select The Modelview Matrix
        GL11.glPushMatrix();                                     // Store The Modelview Matrix
        GL11.glLoadIdentity();                                  // Reset The Modelview Matrix
        
    }
    /**
     * Restores the matrices and enables some 3D only features.
     */
    private void set3DMode() {
    	GL11.glMatrixMode(GL11.GL_PROJECTION);                        // Select The Projection Matrix
        GL11.glPopMatrix();                                      // Restore The Old Projection Matrix
        GL11.glMatrixMode(GL11.GL_MODELVIEW);                         // Select The Modelview Matrix
        GL11.glPopMatrix();                                      // Restore The Old Projection Matrix
        GL11.glEnable(GL11.GL_DEPTH_TEST);
    }
    private void render() {
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT); 
        set2DMode(0, x_max, 0, y_max);
        GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        player.logic();
        player.collision(blocks);
        player.draw();
        for(Block b : blocks) {
            b.draw();
        }
        set3DMode();
    }
    
    private void mainLoop() throws InterruptedException {
        initDisplay(800, 600);
        initResources();
        initGL();
        timer.start();
        while(!Display.isCloseRequested()) {
            Display.sync(60);
            logic();
            render();
            Display.update();
            if(!Display.isVisible()) {
                Thread.sleep(100); //Limits the fps if the windows is not visible.
            }
        }
    }
    private static void destroy() {
        Display.destroy();
        Keyboard.destroy();
        Mouse.destroy();
        //Kill threads here.
    }
    /**
     * Initiates critical resources before rendering begins.
     */
    void initResources() {
        timer = new HerpEngineTime(); //A timer class that returns nanoseconds and shitz.
        player = new Player();
        blocks = new LinkedList<Block>();
        blocks.add(new Block(-400, 400, -300, -100));
        blocks.add(new Block(50, 150, 25, 50));
        blocks.add(new Block(0, 29, 0, 20));
        blocks.add(new Block(100, 400, -100, -60));
    }
     void updateResources() {
        
    }
    
    //gathers all of the members surroinding you the first time we want to render the game
    //not neccecary to do all this computation each frame, just each time the game boots up (maybe)
}